﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace Helper_View
{
    public static class PictureAnalytics
    {
        /// <summary>
        /// 使用颜色数字区间来判断此颜色是否是蓝色
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private static bool IsBlueByArea(Color c)
        {
            //标准蓝色
            int blue = -16776961;
            //误差
            //左偏量
            int lMiss = -400000;
            //右偏量
            int rMiss = 4000000;
            int left = blue - lMiss;
            int right = blue + rMiss;
            //使用判断当前颜色rgb值是否在误差偏量区间来判断是否为蓝色
            if (c.ToArgb() > left && c.ToArgb() < right)
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 使用RBG中的B来判断是否Blue
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private static bool IsBlueByB(Color c)
        {
            if ((float)c.B > 70 && c != Color.White)
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 使用预置蓝色数组来判断此颜色是否是蓝色
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private static bool IsBlueByArray(Color c)
        {
            string[] blues = new string[] { 
                "#0000FF", 
                "#15116B", 
                "#21275B", 
                "#171360", 
                "#140D6A", 
                "#130C74", 
                "#070568", 
                "#100D7E",
                "#030049",
                "#1B126B",
                "#080473",
                "#110E67",
                "#403D82",
                "#0D0575",
                "#6C69AE",
                "#27206E",
                "#7877B0",
                "#170F7F",
                "#2D29BB",
                "#171875",
                "#160F81",
                "#130C7C",
                "#140E68",
                "#262368",
                "#3A3381",
                "#AFAAEA",
                "#2C2865",
                "#AEACD5",
                "#21196C",
                "#7673A3",
                "#8E89C1",
                "#272361",
                "#423B91",
                "#9592C1",
                "#3C3C59",
                "#9896AF",
                "#6D6C8A",
                "#212661"
            };
            foreach (string var in blues)
            {
                if (ColorTranslator.ToHtml(c) == var)
                {
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// 图像三值简化算法
        /// 黑、白、蓝
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns></returns>
        public static Color[,] AnalyticsToThreeColor(Bitmap bmp)
        {
            Color[,] map = new Color[bmp.Width, bmp.Height];
            for (int h = 0; h < bmp.Height; h++)
            {
                string line = "";
                for (int w = 0; w < bmp.Width; w++)
                {
                    Color c = bmp.GetPixel(w, h);
                    int num = (int)((float)(float)c.R * 0.3 + (float)(float)c.G * 0.6 + (float)(float)c.B * 0.1);
                    if (num > 200)
                    {
                        c = Color.White;
                    }
                    if (IsBlackByB(c) || IsBlackByArray(c) || IsBlackByArea(c))
                    {
                        map[w, h] = Color.Black;
                    }
                    else
                    {
                        if (IsBlueByB(c))
                        {
                            map[w, h] = Color.Blue;
                        }
                        else
                        {
                            map[w, h] = Color.White;
                        }
                    }
                }
            }
            return map;
        }
        /// <summary>
        /// 根据颜色的Blue值判断是否为蓝色
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private static bool IsBlackByB(Color c)
        {
            if ((float)c.B < 70)
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 使用颜色数字区间来判断此颜色是否是黑色
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private static bool IsBlackByArea(Color c)
        {
            //标准黑色
            int black = -16777216;
            //误差
            //左偏量
            int lMiss = 2000;
            //右偏量
            int rMiss = 2000;
            int left = black - lMiss;
            int right = black + rMiss;
            if (c.ToArgb() > left && c.ToArgb() < right)
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 使用预置黑色数组来判断此颜色是否是黑色
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        private static bool IsBlackByArray(Color c)
        {
            string[] blacks = new string[] { 
                "#424242",
                "#000000",
                "#020202",
                "#101010",
                "#3E3E3E",
                "#333333",
                "#0B0B0B",
                "#3A3A3A",
                "#3F3F3F",
                "#48484A",
                "#AAAAAA",
                "#A8A8A8",
                "#353535",
                "#A5A5A5",
                "#AAAAAA",
                "#0A0A0A",
                "#0D0D0D",
                "#434343",
                "#444444",
                "#010005",
                "#000100",
                "#0C0C0C"
            };
            foreach (string var in blacks)
            {
                if (ColorTranslator.ToHtml(c) == var)
                {
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// 图像二值简化算法
        /// 黑、白
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns></returns>
        public static Color[,] AnalyticsToTwoColor(Bitmap bmp)
        {
            Color[,] map = new Color[bmp.Width, bmp.Height];
            for (int h = 0; h < bmp.Height; h++)
            {
                string line = "";
                for (int w = 0; w < bmp.Width; w++)
                {
                    Color c = bmp.GetPixel(w, h);
                    int num = (int)((float)(float)c.R * 0.3 + (float)(float)c.G * 0.6 + (float)(float)c.B * 0.1);
                    if (num > 200)
                    {
                        c = Color.White;
                    }
                    else
                    {
                        c = Color.Black;
                    }
                    map[w, h] = c;
                }
            }
            return map;
        }
        /// <summary>
        /// 图像五值化简化方法
        /// 黑、白、灰、蓝、黄
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns></returns>
        public static Color[,] AnalyticsToFiveColor(Bitmap bmp)
        {
            Color[,] map = new Color[bmp.Width, bmp.Height];
            for (int h = 0; h < bmp.Height; h++)
            {
                string line = "";
                for (int w = 0; w < bmp.Width; w++)
                {
                    Color c = bmp.GetPixel(w, h);
                    //黄色 =(红色+绿色)/ 2,取值0..255
                    int yellow = (int)(((float)c.R + (float)c.G) / 2);
                    //灰度 =(黄色+蓝色)/ 2,取值0..255
                    int gray = (int)((yellow + (float)c.B) / 2);
                    //将黄色和蓝色都大于187的视同白色
                    if (yellow > 187 && c.B > 187)
                    {
                        map[w, h] = Color.White;
                        continue;
                    }
                    //将黄色和蓝色都小于153的视同黑色;
                    if (yellow < 153 && c.B < 153)
                    {
                        map[w, h] = Color.Black;
                        continue;
                    }

                    if (yellow < 0.9 * (float)c.B)//如果黄色＜0.9×蓝色，则需进一步进行蓝色细分
                    {
                        if (yellow < 0.8 * (float)c.B)//如果黄色＜0.8×蓝色，视同蓝色
                        {
                            map[w, h] = Color.Blue;
                            continue;
                        }
                        else if (gray < 187)//如果灰度＜187，视同蓝色
                        {
                            map[w, h] = Color.Blue;
                            continue;
                        }
                        else
                        {
                            map[w, h] = Color.Gray;
                            continue;
                        }
                    }
                    else if ((float)c.B < 0.9 * yellow)//如果蓝色＜0.9×黄色，则需进一步进行黄色细分
                    {
                        if ((float)c.B < 0.8 * yellow)//如果蓝色＜0.8×黄色，视同黄色
                        {
                            map[w, h] = Color.Yellow;
                            continue;
                        }
                        else if (gray > 153)//如果灰度＞153，视同黄色
                        {
                            map[w, h] = Color.Yellow;
                            continue;
                        }
                        else
                        {
                            map[w, h] = Color.Gray;
                            continue;
                        }
                    }
                    else//否则则需进一步进行灰色细分
                    {
                        if (gray < 153)//如果灰度＜153，视同黑色
                        {
                            map[w, h] = Color.Black;
                            continue;
                        }
                        else if (gray > 187)//如果灰度＞187，视同白色
                        {
                            map[w, h] = Color.White;
                            continue;
                        }
                        else//否则视同灰色
                        {
                            map[w, h] = Color.Gray;
                            continue;
                        }
                    }
                }
            }
            return map;
        }

        /// <summary>
        /// 将图片切割为四片
        /// </summary>
        /// <param name="map"></param>
        /// <returns></returns>
        public static List<Color[,]> CutPictureToFourPiece(Color[,] map)
        {
            List<Color[,]> list = new List<Color[,]>();
            //左上
            Color[,] map1 = new Color[60, 12];
            //右上
            Color[,] map2 = new Color[60, 12];
            //左下
            Color[,] map3 = new Color[60, 12];
            //右下
            Color[,] map4 = new Color[60, 12];
            GetLeftTop(map, map1);
            GetRightTop(map, map2);
            GetLeftBottom(map, map3);
            GetRightBottom(map, map4);
            list.Add(map1);
            list.Add(map2);
            list.Add(map3);
            list.Add(map4);
            return list;
        }
        /// <summary>
        /// 获取右下角块
        /// </summary>
        /// <param name="map"></param>
        /// <param name="map4"></param>
        private static void GetRightBottom(Color[,] map, Color[,] map4)
        {
            //右下(87,21)
            for (int w = 87; w < map.GetLength(0); w++)
            {
                for (int i = 21; i < 33; i++)
                {
                    map4[w - 87, i - 21] = map[w, i];
                }
            }
        }
        /// <summary>
        /// 获取左下角块
        /// </summary>
        /// <param name="map"></param>
        /// <param name="map3"></param>
        private static void GetLeftBottom(Color[,] map, Color[,] map3)
        {
            //左下(2,4)
            for (int w = 2; w < 49; w++)
            {
                for (int h = 21; h < 33; h++)
                {
                    map3[w - 2, h - 21] = map[w, h];
                }
            }
        }
        /// <summary>
        /// 获取左上角块
        /// </summary>
        /// <param name="map"></param>
        /// <param name="map1"></param>
        private static void GetLeftTop(Color[,] map, Color[,] map1)
        {
            //左上(2,4)
            for (int w = 2; w < 49; w++)
            {
                for (int h = 4; h < 16; h++)
                {
                    map1[w - 2, h - 4] = map[w, h];
                }
            }
        }
        /// <summary>
        /// 获取右上角块
        /// </summary>
        /// <param name="map"></param>
        /// <param name="map2"></param>
        private static void GetRightTop(Color[,] map, Color[,] map2)
        {
            //右上(87,4)
            for (int w = 87; w < map.GetLength(0); w++)
            {
                for (int h = 4; h < 16; h++)
                {
                    map2[w - 87, h - 4] = map[w, h];
                }
            }
        }
        /// <summary>
        /// 将切割后的四片小图收缩宽度
        /// </summary>
        /// <param name="list"></param>
        public static List<Color[,]> PicturePieceContract(List<Color[,]> list)
        {
            List<Color[,]> tempList = new List<Color[,]>();
            foreach (Color[,] map in list)
            {
                Color[,] tempMap;
                int width = map.GetLength(0);
                //计算出去最右边的空列之后的图片宽度
                for (int i = map.GetLength(0) -1 ; i >= 0; i--)
                {
                    if (!IsEmptyColumn(map,i,0,map.GetLength(1)))
                    {
                        width = i + 1;
                        break;
                    }
                }
                //检查保留宽度内是否存在大于4的连续空列
                int emptyCount = 0;//标记连续空列数
                bool flag = false;//标记上一列是否是空列
                int index = 0;//标记扫描列号，此列号为最终宽度
                for (int i = 0; i < width; i++)
                {
                    if (!IsEmptyColumn(map, i, 0, map.GetLength(1)))
                    {
                        flag = false;
                        index = i + 1;
                    }
                    else
                    {
                        if (flag)
                        {
                            emptyCount++;
                        }
                        else
                        {
                            emptyCount = 0;
                            index = i;
                        }
                        if (emptyCount > 3)
                        {
                            break;
                        }
                        flag = true;
                    }
                }
                width = index;
                tempMap = new Color[width,12];
                for (int w = 0; w < width; w++)
                {
                    for (int h = 0; h < 12; h++)
                    {
                        tempMap[w, h] = map[w, h];
                    }
                }
                tempList.Add(tempMap);
            }
            return tempList;
        }
        /// <summary>
        /// 判断某列是否为空白列
        /// </summary>
        /// <param name="map"></param>
        /// <param name="w">起点X</param>
        /// <param name="h">起点Y</param>
        /// <param name="height">扫描线的高度</param>
        /// <returns></returns>
        private static bool IsEmptyColumn(Color[,] map, int w,int h,int height)
        {
            Color c;
            for (int i = 0; i < height; i++)
            {
                c = map[w, h + i];
                if (c != Color.White && !c.IsEmpty)
                {
                    return false;
                }
            }
            return true;
        }
        /// <summary>
        /// 打印字母矩阵区
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static List<Color[,]> Test(List<Color[,]> list)
        {
            List<Color[,]> letterMapList = new List<Color[,]>();
            foreach (Color[,] map in list)
            {
                letterMapList.Add(GetLetterMap(map));
            }
            return letterMapList;
        }
        /// <summary>
        /// 将四块小片段传递过来做匹配，得出每个片段的字母和片段字数
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static List<PieceResult> DoMatch(List<Color[,]> list)
        {
            List<PieceResult> resultList = new List<PieceResult>();
            foreach (Color[,] map in list)
            {
                //获取字母矩阵区
                Color[,] letterMap = GetLetterMap(map);
                //分析出此字母矩阵区内的字母（包括与此字母对应的匹配度）
                PieceResult result = GetLetter(letterMap);
                //分析出此词条的字数
                result.Length = GetLength(map, letterMap.GetLength(0));
                resultList.Add(result);
            }
            return resultList;
        }
        /// <summary>
        /// 获取字母矩阵区
        /// </summary>
        /// <param name="map"></param>
        /// <returns></returns>
        private static Color[,] GetLetterMap(Color[,] map)
        {
            Color[,] letterMap;
            int width = map.GetLength(0);
            //获取字母矩阵区宽度，从左往右扫描每列，遇到点标记则结束
            for (int w = 0; w < map.GetLength(0); w++)
            {
                if (IsPointColumn(map,w))
                {
                    width = w;
                    break;
                }
            }
            letterMap = new Color[width, 12];
            for (int w = 0; w < width; w++)
            {
                for (int h = 0; h < 12; h++)
                {
                    letterMap[w,h] = map[w,h];
                }
            }
            return letterMap;
        }
        /// <summary>
        /// 判断此列是否是点标记列
        /// </summary>
        /// <param name="map"></param>
        /// <param name="w"></param>
        /// <returns></returns>
        private static bool IsPointColumn(Color[,] map, int w)
        {
            if (w <= 3)
            {
                return false;
            }
            for (int i = 0; i < 9; i++)
            {
                if (map[w, i] != Color.White)
                {
                    return false;
                }
            }
            if (map[w, 9] != Color.Black || map[w, 10] != Color.Black)
            {
                return false;
            }
            if (map[w, 11] != Color.White)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 分析出此词条的字母
        /// </summary>
        /// <param name="map"></param>
        /// <param name="result"></param>
        /// <param name="index"></param>
        private static PieceResult GetLetter(Color[,] map)
        {
            PieceResult result = new PieceResult();
            //foreach (LetterDictionary.Letter letter in LetterDictionary.Letters)
            //{
            //    //先将两个矩阵长宽处理为一样，同时将Color矩阵转变为int矩阵
            //    List<int[,]> maps = ToSameSize(map,letter);
            //    int[,] picMap = maps[0];
            //    int[,] letterMap = maps[1];
            //    //获取两矩阵的相似度
            //    double matchRatio = GetMatchRatio(picMap,letterMap);
            //    if (result.MatchRatio < matchRatio)
            //    {
            //        result.Name = letter.name;
            //        result.MatchRatio = matchRatio;
            //    }
            //}
            return result;
        }
        /// <summary>
        /// 获取两矩阵的相似度（匹配点/（宽*高））
        /// </summary>
        /// <param name="picMap"></param>
        /// <param name="letterMap"></param>
        /// <returns></returns>
        private static double GetMatchRatio(int[,] picMap, int[,] letterMap)
        {
            double sameCount = 0;
            for (int w = 0; w < picMap.GetLength(0); w++)
            {
                for (int h = 0; h < 12; h++)
                {
                    if (picMap[w, h] == letterMap[w, h])
                    {
                        sameCount++;
                    }
                }
            }
            double matchRatio = sameCount / (picMap.GetLength(0) * picMap.GetLength(1));
            return matchRatio;
        }
        /// <summary>
        /// 两个矩阵匹配前的处理
        /// 将两个矩阵长宽处理为一样，同时将Color矩阵转变为int矩阵
        /// </summary>
        /// <param name="map"></param>
        /// <param name="letter"></param>
        /// <returns></returns>
        //private static List<int[,]> ToSameSize(Color[,] map, LetterDictionary.Letter letter)
        //{
        //    List<int[,]> list = new List<int[,]>();
        //    int width = map.GetLength(0) > letter.map.GetLength(0) ? map.GetLength(0) : letter.map.GetLength(0);
        //    int[,] picMap = new int[width,12];
        //    int[,] letterMap = new int[width, 12];
        //    for (int w = 0; w < map.GetLength(0); w++)
        //    {
        //        for (int h = 0; h < 12; h++)
        //        {
        //            picMap[w, h] = map[w, h] == Color.Black ? 1 : 0;
        //        }
        //    }
        //    for (int w = 0; w < letter.map.GetLength(0); w++)
        //    {
        //        for (int h = 0; h < 12; h++)
        //        {
        //            letterMap[w, h] = letter.map[w, h];
        //        }
        //    }
        //    list.Add(picMap);
        //    list.Add(letterMap);
        //    return list;
        //}
        /// <summary>
        /// 分析出此词条的字数
        /// </summary>
        /// <param name="map"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private static int GetLength(Color[,] map, int index)
        {
            int letterWidth = map.GetLength(0) - index;
            if (letterWidth < 15)
            {
                return 1;
            }
            else if (letterWidth < 30)
            {
                return 2;
            }
            else
            {
                return 3;
            }
        }
        /// <summary>
        /// 根据分析结果，按照取“最长”或“最短”词条对应的字母的原则返回答案
        /// </summary>
        /// <param name="resultList"></param>
        /// <returns></returns>
        public static string GetAnswer(List<PieceResult> resultList)
        {
            int length = 0;
            Dictionary<int, int> dic = new Dictionary<int, int>();
            dic.Add(1, 0);
            dic.Add(2, 0);
            dic.Add(3, 0);
            foreach (PieceResult var in resultList)
            {
                dic[var.Length] = dic[var.Length] + 1;
            }
            for (int i = 1; i <= 3; i++)
            {
                if (dic[i] == 1)
                {
                    length = i;
                    break;
                }
                else
                {
                    length = resultList[0].Length;
                }
            }
            foreach (PieceResult var in resultList)
            {
                if (var.Length == length)
                {
                    return var.Name;
                }
            }
            return "0";
        }
    }
}
